package cn.mujiankeji.mbrowser.界面.组件.代码框

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import cn.mujiankeji.mbrowser.工具.mlog
import kotlinx.coroutines.delay

/**
 * 代码格式化类型
 */
object 代码格式化类型 {
    const val HTML = 1
    const val JSON = 2
    const val TXT = 3
}

/**
 * 代码编辑回调接口
 */
interface 代码编辑回调 {
    /**
     * 当代码被编辑时调用
     * @param 原始代码 编辑前的代码
     * @param 编辑后代码 编辑后的代码
     * @param 节点标识 被编辑节点的标识，用于定位
     */
    fun 代码已编辑(原始代码: String, 编辑后代码: String, 节点标识: String)
}

/**
 * 代码项视图
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun 代码项视图(
    项: 代码项,
    缩进大小: androidx.compose.ui.unit.Dp,
    已选中: Boolean,
    点击回调: () -> Unit,
    长按回调: () -> Unit
) {
    // 如果文本为空或只包含空白字符，不显示
    if (项.文本?.text?.isBlank() == true) return
    
    // 使用rememberUpdatedState确保已展开状态变化时重组
    val 是否已展开 by rememberUpdatedState(项.已展开)
    
    val 缩进级别 = if (项.标识.contains("-")) 项.标识.split("-").size - 1 else 0
    val 左内边距 = 缩进大小 * 缩进级别.toInt()
    
    val 背景颜色 = if (已选中) 代码颜色.选中背景 else 代码颜色.背景
    
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .background(背景颜色)
            .combinedClickable(
                onClick = { 点击回调() },
                onLongClick = { 长按回调() }
            )
            .padding(start = 左内边距, end = 8.dp, top = 4.dp, bottom = 4.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        // 展开/折叠图标
        if (项.是节点开始) {
            val 旋转角度 by animateFloatAsState(
                targetValue = if (是否已展开) 90f else 0f,
                label = "rotation"
            )
            
            Icon(
                imageVector = Icons.Default.KeyboardArrowRight,
                contentDescription = if (是否已展开) "折叠" else "展开",
                modifier = Modifier
                    .size(24.dp)
                    .rotate(旋转角度),
                tint = 代码颜色.文本颜色.copy(alpha = 0.7f)
            )
        } else {
            Box(modifier = Modifier.size(24.dp))
        }
        
        // 代码文本
        Text(
            text = 项.文本 ?: AnnotatedString(""),
            style = TextStyle(
                fontFamily = FontFamily.Monospace,
                fontSize = 14.sp
            ),
            modifier = Modifier.padding(start = 4.dp)
        )
    }
}

/**
 * 代码格式化视图
 */
@Composable
fun 代码格式化视图(
    代码: String,
    类型: Int = 代码格式化类型.HTML,
    modifier: Modifier = Modifier,
    项目选中回调: ((代码项) -> Unit)? = null,
    代码编辑回调: 代码编辑回调? = null
) {
    // 自动检测系统是否为深色主题
    val 是系统深色主题 = isSystemInDarkTheme()
    
    // 设置颜色模式
    DisposableEffect(是系统深色主题) {
        代码颜色.设置黑暗模式(是系统深色主题)
        onDispose { }
    }
    
    // 使用记忆状态存储当前代码，用于检测变化
    var 当前代码 by remember { mutableStateOf("") }
    
    // 创建UI展示项列表
    val 代码项列表 = remember { mutableStateListOf<代码项>() }
    
    // 选中的项
    var 选中项索引 by remember { mutableStateOf(-1) }
    
    // 强制重组的状态
    var 更新计数 by remember { mutableStateOf(0) }
    
    // 记录是否已经自动展开过标签
    var 已自动展开标签 by remember { mutableStateOf(false) }
    
    // 解析代码节点列表
    val 代码节点列表 = remember { mutableStateListOf<代码节点>() }
    
    // 编辑对话框状态
    var 显示编辑对话框 by remember { mutableStateOf(false) }
    var 当前编辑项 by remember { mutableStateOf<代码项?>(null) }
    var 编辑文本 by remember { mutableStateOf("") }
    
    // 检测代码变化并重新解析
    LaunchedEffect(代码, 类型) {
        mlog("代码格式化视图: 代码内容变化，重新解析")
        // 如果代码没有变化，不进行重新解析
        if (代码 == 当前代码) return@LaunchedEffect
        
        当前代码 = 代码
        
        // 重置自动展开标记
        已自动展开标签 = false
        
        // 清空旧的节点列表
        代码节点列表.clear()
        
        // 解析新代码
        when (类型) {
            代码格式化类型.HTML -> 代码格式化工具.解析HTML(代码)
            代码格式化类型.JSON -> 代码格式化工具.解析JSON(代码)
            else -> null
        }?.let {
            代码节点列表.addAll(it)
        }
        
        // 清空旧的项列表
        代码项列表.clear()
        
        // 重新初始化列表项
        if (代码节点列表.isNotEmpty()) {
            代码节点列表.forEachIndexed { index, node ->
                // 过滤掉空文本节点
                if (node.文本?.text?.isBlank() == true) return@forEachIndexed
                
                val item = 代码项(
                    文本 = node.文本,
                    标识 = (index + 1).toString(),
                    节点 = node,
                    是节点开始 = node.子节点列表 != null,
                    是节点结束 = node.子节点列表 != null
                )
                代码项列表.add(item)
            }
            
            // 更新计数触发重组
            更新计数++
        }
    }
    
    // 列表状态
    val 列表状态 = rememberLazyListState()
    
    // 自动展开第一级和第二级节点
    LaunchedEffect(代码, 代码项列表.size) {
        // 如果已经自动展开过，或者列表为空，则不执行
        if (已自动展开标签 || 代码项列表.isEmpty()) {
            return@LaunchedEffect
        }
        
        mlog("代码格式化视图: 尝试自动展开第一级和第二级节点")
        
        // 标记已自动展开，防止重复执行
        已自动展开标签 = true
        
        // 第一轮：找出并展开所有第一级节点
        val 一级节点索引列表 = mutableListOf<Int>()
        代码项列表.forEachIndexed { index, item ->
            if (item.是节点开始 && !item.已展开 && !item.标识.contains("-")) {
                一级节点索引列表.add(index)
            }
        }
        
        // 展开所有第一级节点
        if (一级节点索引列表.isNotEmpty()) {
            mlog("代码格式化视图: 找到 ${一级节点索引列表.size} 个第一级节点")
            一级节点索引列表.forEach { index ->
                if (index < 代码项列表.size) {
                    展开节点(代码项列表, index)
                    delay(10) // 短暂延迟确保UI更新
                }
            }
            
            // 更新计数触发重组
            更新计数++
            
            // 等待第一级节点展开完成
            delay(50)
        }
        
        // 第二轮：找出并展开所有第二级节点
        val 二级节点索引列表 = mutableListOf<Int>()
        代码项列表.forEachIndexed { index, item ->
            // 检查是否为第二级节点（标识中只有一个"-"）
            if (item.是节点开始 && !item.已展开 && 
                item.标识.contains("-") && 
                item.标识.count { it == '-' } == 1) {
                二级节点索引列表.add(index)
            }
        }
        
        // 展开所有第二级节点
        if (二级节点索引列表.isNotEmpty()) {
            mlog("代码格式化视图: 找到 ${二级节点索引列表.size} 个第二级节点")
            二级节点索引列表.forEach { index ->
                if (index < 代码项列表.size) {
                    展开节点(代码项列表, index)
                    delay(5) // 短暂延迟确保UI更新
                }
            }
            
            // 更新计数触发重组
            更新计数++
        }
    }
    
    // 处理点击展开/折叠
    fun 处理项目点击(索引: Int) {
        // 确保索引有效
        if (索引 < 0 || 索引 >= 代码项列表.size) return
        
        // 选中项
        选中项索引 = 索引
        val 当前项 = 代码项列表[索引]
        项目选中回调?.invoke(当前项)
        
        // 如果是节点开始项，则展开或折叠
        if (当前项.是节点开始) {
            mlog("代码格式化视图: 点击项目，尝试展开/折叠，当前状态: ${当前项.已展开}")
            if (当前项.已展开) {
                折叠节点(代码项列表, 索引)
            } else {
                展开节点(代码项列表, 索引)
            }
            // 触发重组
            更新计数++
        }
    }
    
    // 处理长按编辑
    fun 处理项目长按(索引: Int) {
        // 确保索引有效
        if (索引 < 0 || 索引 >= 代码项列表.size) return
        
        // 获取当前项
        val 当前项 = 代码项列表[索引]
        
        // 如果没有编辑回调，则不处理
        if (代码编辑回调 == null) {
            mlog("代码格式化视图: 长按项目，但没有提供编辑回调")
            return
        }
        
        // 设置当前编辑项和编辑文本
        当前编辑项 = 当前项
        编辑文本 = 当前项.文本?.text ?: ""
        
        // 显示编辑对话框
        显示编辑对话框 = true
        
        mlog("代码格式化视图: 长按项目，打开编辑对话框: ${当前项.标识}")
    }
    
    // 编辑对话框
    if (显示编辑对话框 && 当前编辑项 != null) {
        AlertDialog(
            onDismissRequest = { 显示编辑对话框 = false },
            title = { Text("编辑代码") },
            text = {
                BasicTextField(
                    value = 编辑文本,
                    onValueChange = { 编辑文本 = it },
                    textStyle = TextStyle(
                        fontFamily = FontFamily.Monospace,
                        fontSize = 14.sp,
                        color = 代码颜色.文本颜色
                    ),
                    cursorBrush = SolidColor(代码颜色.文本颜色),
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(vertical = 8.dp)
                )
            },
            confirmButton = {
                TextButton(
                    onClick = {
                        // 获取原始代码和编辑后代码
                        val 原始代码 = 当前编辑项!!.文本?.text ?: ""
                        val 编辑后代码 = 编辑文本
                        
                        // 如果代码有变化，调用回调
                        if (原始代码 != 编辑后代码) {
                            代码编辑回调?.代码已编辑(
                                原始代码 = 原始代码,
                                编辑后代码 = 编辑后代码,
                                节点标识 = 当前编辑项!!.标识
                            )
                            
                            // 更新当前项的文本
                            当前编辑项!!.文本 = AnnotatedString(编辑后代码)
                            
                            // 触发重组
                            更新计数++
                            
                            mlog("代码格式化视图: 编辑完成，代码已更新: ${当前编辑项!!.标识}")
                        }
                        
                        // 关闭对话框
                        显示编辑对话框 = false
                    }
                ) {
                    Text("确定")
                }
            },
            dismissButton = {
                TextButton(
                    onClick = { 显示编辑对话框 = false }
                ) {
                    Text("取消")
                }
            }
        )
    }
    
    Surface(
        modifier = modifier,
        color = 代码颜色.背景
    ) {
        if (代码项列表.isEmpty()) {
            // 如果没有解析出代码项，显示原始文本
            Text(
                text = 代码,
                style = TextStyle(
                    fontFamily = FontFamily.Monospace,
                    fontSize = 14.sp
                ),
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
            )
        } else {
            LazyColumn(
                state = 列表状态,
                modifier = Modifier.fillMaxWidth()
            ) {
                itemsIndexed(
                    items = 代码项列表,
                    key = { index, item -> "${item.标识}-${item.已展开}-$更新计数-$index" }
                ) { index, item ->
                    // 过滤掉空白文本的项
                    if (item.文本?.text?.isBlank() == true) return@itemsIndexed
                    
                    代码项视图(
                        项 = item,
                        缩进大小 = 16.dp,
                        已选中 = index == 选中项索引,
                        点击回调 = { 处理项目点击(index) },
                        长按回调 = { 处理项目长按(index) }
                    )
                }
            }
        }
    }
}

/**
 * 展开节点
 */
fun 展开节点(项列表: MutableList<代码项>, 位置: Int) {
    // 检查位置是否有效
    if (位置 < 0 || 位置 >= 项列表.size) {
        mlog("代码格式化视图: 展开节点失败，位置无效: $位置, 列表大小: ${项列表.size}")
        return
    }
    
    val 节点 = 项列表[位置]
    if (!节点.是节点开始 || 节点.已展开) {
        mlog("代码格式化视图: 展开节点失败，节点不是开始节点或已经展开")
        return
    }
    
    // 标记为已展开
    节点.已展开 = true
    mlog("代码格式化视图: 节点已标记为展开: ${节点.标识}")
    
    // 更新显示文本
    节点.文本 = 节点.节点.文本
    
    // 没有子节点，不处理
    if (节点.节点.子节点列表.isNullOrEmpty()) {
        mlog("代码格式化视图: 节点没有子节点，不需要展开")
        return
    }
    
    var 插入位置 = 位置 + 1
    
    // 插入子节点
    节点.节点.子节点列表?.forEachIndexed { index, childNode ->
        // 过滤掉空白文本节点
        if (childNode.文本?.text?.isBlank() == true) return@forEachIndexed
        
        val item = 代码项(
            文本 = childNode.文本,
            标识 = "${节点.标识}-$index",
            节点 = childNode,
            是节点开始 = childNode.子节点列表 != null,
            是节点结束 = childNode.子节点列表 != null
        )
        
        项列表.add(插入位置, item)
        插入位置++
    }
    
    // 插入结束标签
    if (节点.节点.结束文本 != null) {
        val 结束项 = 代码项(
            文本 = 节点.节点.结束文本,
            标识 = 节点.标识,
            节点 = 节点.节点,
            是节点开始 = false,
            是节点结束 = true
        )
        项列表.add(插入位置, 结束项)
    }
    
    mlog("代码格式化视图: 节点展开完成，子节点数量: ${节点.节点.子节点列表?.size ?: 0}")
}

/**
 * 折叠节点
 */
private fun 折叠节点(项列表: MutableList<代码项>, 位置: Int) {
    // 检查位置是否有效
    if (位置 < 0 || 位置 >= 项列表.size) {
        mlog("代码格式化视图: 折叠节点失败，位置无效: $位置, 列表大小: ${项列表.size}")
        return
    }
    
    val 节点 = 项列表[位置]
    if (!节点.是节点开始 || !节点.已展开) {
        mlog("代码格式化视图: 折叠节点失败，节点不是开始节点或已经折叠")
        return
    }
    
    // 标记为已折叠
    节点.已展开 = false
    mlog("代码格式化视图: 节点已标记为折叠: ${节点.标识}")
    
    // 更新显示文本
    if (节点.节点.结束文本 != null) {
        节点.文本 = 代码格式化工具.创建折叠文本(节点.节点.文本, 节点.节点.结束文本)
    }
    
    // 删除所有子项
    var i = 位置 + 1
    var 删除计数 = 0
    while (i < 项列表.size) {
        val 项 = 项列表[i]
        
        // 如果遇到同级或上级项，结束删除
        if (项.标识.length <= 节点.标识.length) {
            // 如果是当前节点的结束标签，也要删除
            if (项.标识 == 节点.标识 && 项.是节点结束) {
                项列表.removeAt(i)
                删除计数++
            }
            break
        }
        
        项列表.removeAt(i)
        删除计数++
    }
    
    mlog("代码格式化视图: 节点折叠完成，删除了 $删除计数 个子项")
} 